package com.coder.algorithm.offer_2;

import java.util.Locale;

/**
 * 表示数值的字符串
 * <p>
 * 遵循模式 `A[.[B]][e|EC]` 或者 `.B[e|EC]`
 * A 为数值的整数部分
 * B 为紧跟着小数点的小数部分
 * C 为紧跟着 'e' 或 'E' 的指数部分
 *
 * @author yuhushuan
 * @date 2020/6/15 08:47
 */
public class _20_1_NumericStrings {
    public static void main(String[] args) {

        print("+100");
        print("5e2");
        print("-123");
        print("3.1416");
        print("-1E-16");

        print("12e");
        print("1a3.14");
        print("1.2.3");
        print("+-5");
        print("12e+5.4");

    }

    private static void print(String str) {
        System.out.println(String.format(Locale.getDefault(), "字符串 \"%s\" 表示数值为 %b",
                str, isNumeric(str)));
    }

    private static boolean isNumeric(String str) {
        if (str == null) {
            return false;
        }
        int[] index = {0};// 用于记录当前字符位置

        // 判断 A
        boolean isNumeric = scanInteger(str, index);

        // 判断 B
        if (index[0] < str.length() && '.' == str.charAt(index[0])) {
            index[0]++;

            // 下面一行代码用 '||' 的原因
            // 1、小数可以没有整数部分，如 .123 等于 0.123
            // 2、小数点后面可以没有数字，如 233. 等于 233.0
            // 3、当然，小数点前面和后面可以都有数字，如 233。666
            isNumeric = scanUnsignedInteger(str, index) || isNumeric;
        }

        // 判断 C
        if (index[0] < str.length() && 'e' == str.charAt(index[0]) | 'E' == str.charAt(index[0])) {
            index[0]++;

            // 下面一行代码用 '&&' 的原因
            // 1、当 e 或 E 前面没有数字时，整个字符串不能表示数字，如 .e1、e1；
            // 2、当 e 或 E 后面没有数字时，整个字符串不能表示数字，如 12e、12e+5.4
            isNumeric = scanInteger(str, index) && isNumeric;
        }

        return isNumeric && index[0] == str.length();
    }

    private static boolean scanInteger(String str, int[] index) {
        if (index[0] < str.length() && (str.charAt(index[0]) == '-' || str.charAt(index[0]) == '+')) {
            index[0]++;
        }
        return scanUnsignedInteger(str, index);
    }

    private static boolean scanUnsignedInteger(String str, int[] index) {
        int start = index[0];
        while (index[0] < str.length() && str.charAt(index[0]) >= '0' && str.charAt(index[0]) <= '9') {
            index[0]++;
        }
        return index[0] > start;
    }


}
